﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Reflection;
using System.Windows.Forms;
using HML.Design;

namespace HML
{
    /// <summary>
    /// 圆角容器
    /// </summary>
    [Description("圆角容器")]
    [DefaultProperty("RoundSize")]
    [TypeConverter(typeof(PropertyOrderConverter))]
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(RoundContainer), "Controls.RoundContainer.Resources.RoundContainer.bmp")]
    public class RoundContainer : DpiContainerControl, ISkinObject
    {
        #region 主题

        private SkinObjectXmlMetadata skinObjectXmlMetadata = null;
        /// <summary>
        /// 主题对象在主题文件信息
        /// </summary>
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual SkinObjectXmlMetadata SkinObjectXmlMetadata
        {
            get
            {
                if (this.skinObjectXmlMetadata == null)
                    this.skinObjectXmlMetadata = new SkinObjectXmlMetadata(Assembly.GetAssembly(typeof(RoundContainer)).GetName().Name, typeof(RoundContainer).Name);

                return this.skinObjectXmlMetadata;
            }
        }

        private SkinController skinController = null;
        /// <summary>
        /// 主题控制器
        /// </summary>
        [Description("主题控制器")]
        [Category("杂项")]
        [PropertyOrder(-360)]
        [DefaultValue(null)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinController SkinController
        {
            get { return this.skinController; }
            set
            {
                if (this.skinController == value)
                    return;

                if (this.skinController != null)
                    this.skinController.RemoveSkinObject(this);

                this.skinController = value;

                if (this.skinController != null)
                    this.skinController.AddSkinObject(this);
            }
        }

        private SkinEnabledState skinEnabled= SkinEnabledState.Auto;
        /// <summary>
        /// 主题是否启用
        /// </summary>
        [Description("主题是否启用")]
        [Category("杂项")]
        [PropertyOrder(-300)]
        [DefaultValue(SkinEnabledState.Auto)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinEnabledState SkinEnabled
        {
            get { return this.skinEnabled; }
            set
            {
                if (this.skinEnabled == value)
                    return;

                this.skinEnabled = value;
                this.OnSkinChanged();
            }
        }

        private SkinStyle skinStyle = SkinStyle.Normal;
        /// <summary>
        /// 主题风格
        /// </summary>
        [Description("主题风格")]
        [Category("杂项")]
        [PropertyOrder(-260)]
        [DefaultValue(SkinStyle.Normal)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinStyle SkinStyle
        {
            get { return this.skinStyle; }
            set
            {
                if (this.skinStyle == value)
                    return;

                this.skinStyle = value;
                this.OnSkinChanged();
            }
        }

        private StyleAppearanceObject stateAppearance;
        /// <summary>
        /// 风格外观
        /// </summary>
        [Description("风格外观")]
        [Category("杂项")]
        [PropertyOrder(-200)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public StyleAppearanceObject StyleAppearance
        {
            get
            {
                if (this.stateAppearance == null)
                    this.stateAppearance = new StyleAppearanceObject(this, null);
                return this.stateAppearance;
            }
        }

        /// <summary>
        /// 主题已更改
        /// </summary>
        public virtual void OnSkinChanged()
        {
            SkinManager.SyncSkinValueToProperty(this);
            this.Invalidate();
        }

        private ISkinObject followSkinObject = null;
        /// <summary>
        /// 主题设置跟随指定主题对象（自己的设置不再生效，提供给代码使用）
        /// </summary>
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Localizable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual ISkinObject FollowSkinObject
        {
            get { return this.followSkinObject; }
            set
            {
                if (this.followSkinObject == value)
                    return;

                this.followSkinObject = value;
                this.OnSkinChanged();
            }
        }

        public virtual bool GetSkinObjectSkinStateCore()
        {
            return SkinManager.GetSkinObjectSkinState(this.FollowSkinObject ?? this);
        }

        void ISkinObject.InitializeInvalidate()
        {
            throw new NotImplementedException();
        }

        void ISkinObject.Invalidate()
        {
            this.Invalidate();
        }

        #endregion

        #region 停用事件

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event ScrollEventHandler Scroll
        {
            add { base.Scroll += value; }
            remove { base.Scroll -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler RightToLeftChanged
        {
            add { base.RightToLeftChanged += value; }
            remove { base.RightToLeftChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackgroundImageChanged
        {
            add { base.BackgroundImageChanged += value; }
            remove { base.BackgroundImageChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackgroundImageLayoutChanged
        {
            add { base.BackgroundImageLayoutChanged += value; }
            remove { base.BackgroundImageLayoutChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackColorChanged
        {
            add { base.BackColorChanged += value; }
            remove { base.BackColorChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ForeColorChanged
        {
            add { base.ForeColorChanged += value; }
            remove { base.ForeColorChanged -= value; }
        }

        #endregion

        #region 新增属性

        private RoundCorner roundSize = new RoundCorner(10, 10, 10, 10);
        /// <summary>
        /// 圆角Size
        /// </summary>
        [Description("圆角Size")]
        [Category("杂项")]
        [PropertyOrder(-198)]
        [DefaultValue(typeof(RoundCorner), "10, 10,  10, 10")]
        public RoundCorner RoundSize
        {
            get { return this.roundSize; }
            set
            {
                if (value.LeftTop < 0)
                    value.LeftTop = 0;

                if (value.RightTop < 0)
                    value.RightTop = 0;

                if (value.RightBottom < 0)
                    value.RightBottom = 0;

                if (value.LeftBottom < 0)
                    value.LeftBottom = 0;

                if (this.roundSize == value)
                    return;

                this.roundSize = value;

                if (this.TrapeziformCutEnabled)
                {
                    this.SetControlShape();
                }
                this.Invalidate();
            }
        }

        private int borderThickness = 1;
        /// <summary>
        /// 边框厚度
        /// </summary>
        [Description("边框厚度")]
        [Category("杂项")]
        [PropertyOrder(-196)]
        [DefaultValue(1)]
        public int BorderThickness
        {
            get { return this.borderThickness; }
            set
            {
                if (this.borderThickness == value || value < 0)
                    return;

                this.borderThickness = value;
                this.Invalidate();
            }
        }

        private int gradientAngle = 180;
        /// <summary>
        /// 渐变开始色角度
        /// </summary>
        [Description("渐变开始色角度")]
        [Category("杂项")]
        [PropertyOrder(-194)]
        [DefaultValue(180)]
        [Bindable(true)]
        [Editor(typeof(IntAngleEditor), typeof(UITypeEditor))]
        public int GradientAngle
        {
            get { return this.gradientAngle; }
            set
            {
                if (value < 0)
                    value = 0;
                if (value > 360)
                    value = 360;
                if (this.gradientAngle == value)
                    return;

                this.gradientAngle = value;
                this.Invalidate();
            }
        }

        private bool trapeziformCutEnabled = false;
        /// <summary>
        /// 是否剪切为不规则形状
        /// </summary>
        [Description("是否剪切为不规则形状")]
        [Category("杂项")]
        [PropertyOrder(-192)]
        [DefaultValue(false)]
        public bool TrapeziformCutEnabled
        {
            get { return this.trapeziformCutEnabled; }
            set
            {
                if (this.trapeziformCutEnabled == value)
                    return;

                this.trapeziformCutEnabled = value;

                if (this.TrapeziformCutEnabled)
                {
                    this.SetControlShape();
                }
                else
                {
                    this.Region = new Region(this.ClientRectangle);
                }
                this.Invalidate();
            }
        }

        #endregion

        #region 重写属性

        protected override Size DefaultSize
        {
            get { return new Size(200, 100); }
        }

        #endregion

        #region 停用属性

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override bool AutoScroll
        {
            get { return base.AutoScroll; }
            set { base.AutoScroll = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Size AutoScrollMinSize
        {
            get { return base.AutoScrollMinSize; }
            set { base.AutoScrollMinSize = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Point AutoScrollPosition
        {
            get { return base.AutoScrollPosition; }
            set { base.AutoScrollPosition = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Size AutoScrollMargin
        {
            get { return base.AutoScrollMargin; }
            set { base.AutoScrollMargin = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override RightToLeft RightToLeft
        {
            get { return base.RightToLeft; }
            set { base.RightToLeft = value; }
        }

        [Bindable(false)]
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override string Text
        {
            get { return base.Text; }
            set { base.Text = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Image BackgroundImage
        {
            get { return base.BackgroundImage; }
            set { base.BackgroundImage = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new ImageLayout BackgroundImageLayout
        {
            get { return base.BackgroundImageLayout; }
            set { base.BackgroundImageLayout = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Color BackColor
        {
            get { return this.StyleAppearance.BackStartColor; }
            set { }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Color ForeColor
        {
            get { return this.StyleAppearance.TextColor; }
            set { }
        }

        #endregion

        public RoundContainer()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);

            this.SuspendLayout();
            this.AutoScroll = false;
            this.AutoScrollMinSize = new Size(0, 0);
            this.AutoScrollMargin = new Size(0, 0);
            this.OnSkinChanged();
            this.ResumeLayout();
        }

        #region 重写

        protected override void OnScaleDpiChangedInitialize()
        {
            this.Invalidate();
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            base.OnPaintBackground(e);

            Graphics g = e.Graphics;

            SolidBrush back_sb = new SolidBrush(base.BackColor);
            g.FillRectangle(back_sb, this.ClientRectangle);
            back_sb.Dispose();

        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;

            int scale_borderthicknes = this.BorderThickness <= 1 ? 1 : (int)Math.Ceiling(this.BorderThickness * this.ScaleDpi);
            RoundCorner rc = new RoundCorner((int)Math.Ceiling(this.RoundSize.LeftTop * this.ScaleDpi), (int)Math.Ceiling(this.RoundSize.RightTop * this.ScaleDpi), (int)Math.Ceiling(this.RoundSize.RightBottom * this.ScaleDpi), (int)Math.Ceiling(this.RoundSize.LeftBottom * this.ScaleDpi));
            GraphicsPath gp = ControlHelper.AdjustCircularPath(ControlHelper.TransformRectangle(this.ClientRectangle, scale_borderthicknes), rc.LeftTop, rc.RightTop, rc.RightBottom, rc.LeftBottom);

            //背景
            LinearGradientBrush content_lgb = new LinearGradientBrush(this.ClientRectangle, this.StyleAppearance.BackStartColor, this.StyleAppearance.BackEndColor, (this.GradientAngle - 180));
            g.FillPath(content_lgb, gp);
            content_lgb.Dispose();

            //边框
            if (scale_borderthicknes > 0)
            {
                Pen border_pen = new Pen(this.StyleAppearance.BorderColor, scale_borderthicknes);
                g.DrawPath(border_pen, gp);
                border_pen.Dispose();
            }

            gp.Dispose();
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            if (this.TrapeziformCutEnabled)
            {
                this.SetControlShape();
            }
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 设置控件形状
        /// </summary>
        private void SetControlShape()
        {
            RoundCorner rc = new RoundCorner((int)Math.Ceiling(this.RoundSize.LeftTop * this.ScaleDpi), (int)Math.Ceiling(this.RoundSize.RightTop * this.ScaleDpi), (int)Math.Ceiling(this.RoundSize.RightBottom * this.ScaleDpi), (int)Math.Ceiling(this.RoundSize.LeftBottom * this.ScaleDpi));
            GraphicsPath gp = ControlHelper.AdjustCircularPath(this.ClientRectangle, rc.LeftTop, rc.RightTop, rc.RightBottom, rc.LeftBottom);
            this.Region = new Region(gp);
            gp.Dispose();
        }

        #endregion

        #region 外观

        public class StyleAppearanceObject : AppearanceObjectBase
        {
            internal StyleAppearanceObject(ISkinObject owner, AppearanceObjectBase parent) : base(owner, parent) { }

            #region 属性

            private Color skinBorderColor = Color.Empty;
            private readonly Color defaultBorderColor = SystemColors.ActiveCaption;
            private Color borderColor = Color.Empty;
            /// <summary>
            /// 边框颜色
            /// </summary>
            [Description("边框颜色")]
            [PropertyOrder(-198)]
            [SkinProperty(true, false)]
            public Color BorderColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore())
                    {
                        return this.skinBorderColor;
                    }

                    if (this.borderColor != Color.Empty)
                    {
                        return this.borderColor;
                    }

                    return this.defaultBorderColor;
                }
                set
                {
                    if (this.borderColor == value)
                        return;

                    this.borderColor = value;
                    this.Invalidate();
                }
            }
            private bool ShouldSerializeBorderColor()
            {
                return this.borderColor != Color.Empty;
            }
            private void ResetBorderColor()
            {
                this.borderColor = Color.Empty;
                this.Invalidate();
            }

            private Color skinBackStartColor = Color.Empty;
            private readonly Color defaultBackStartColor = SystemColors.Control;
            private Color backStartColor = Color.Empty;
            /// <summary>
            /// 背景渐变开始颜色
            /// </summary>
            [Description("背景渐变开始颜色")]
            [PropertyOrder(-196)]
            [SkinProperty(true, true)]
            public Color BackStartColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore() && this.skinBackStartColor != Color.Empty)
                    {
                        return this.skinBackStartColor;
                    }

                    if (this.backStartColor != Color.Empty)
                    {
                        return this.backStartColor;
                    }

                    if (((Control)this.owner).Parent != null)
                    {
                        return ((Control)this.owner).Parent.BackColor;
                    }

                    return this.defaultBackStartColor;
                }
                set
                {
                    if (this.backStartColor == value)
                        return;

                    this.backStartColor = value;
                    ((Control)this.owner).Invalidate();

                    foreach (Control control in ((Control)this.owner).Controls)
                    {
                        control.GetType().GetMethod("OnParentBackColorChanged", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(control, new object[] { EventArgs.Empty });
                    }
                }

            }
            private bool ShouldSerializeBackStartColor()
            {
                return this.backStartColor != Color.Empty;
            }
            private void ResetBackStartColor()
            {
                this.backStartColor = Color.Empty;
                ((Control)this.owner).Invalidate();

                foreach (Control control in ((Control)this.owner).Controls)
                {
                    control.GetType().GetMethod("OnParentBackColorChanged", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(control, new object[] { EventArgs.Empty });
                }
            }

            private Color skinBackEndColor = Color.Empty;
            private readonly Color defaultBackEndColor = SystemColors.Control;
            private Color backEndColor = Color.Empty;
            /// <summary>
            /// 背景渐变结束颜色
            /// </summary>
            [Description("背景渐变结束颜色")]
            [PropertyOrder(-194)]
            [SkinProperty(true, true)]
            public Color BackEndColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore() && this.skinBackEndColor != Color.Empty)
                    {
                        return this.skinBackEndColor;
                    }

                    if (this.backEndColor != Color.Empty)
                    {
                        return this.backEndColor;
                    }

                    if (((Control)this.owner).Parent != null)
                    {
                        return ((Control)this.owner).Parent.BackColor;
                    }

                    return this.defaultBackEndColor;
                }
                set
                {
                    if (this.backEndColor == value)
                        return;

                    this.backEndColor = value;
                    ((Control)this.owner).Invalidate();

                    foreach (Control control in ((Control)this.owner).Controls)
                    {
                        control.GetType().GetMethod("OnParentBackColorChanged", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(control, new object[] { EventArgs.Empty });
                    }
                }
            }
            private bool ShouldSerializeBackEndColor()
            {
                return this.backEndColor != Color.Empty;
            }
            private void ResetBackEndColor()
            {
                this.backEndColor = Color.Empty;
                ((Control)this.owner).Invalidate();

                foreach (Control control in ((Control)this.owner).Controls)
                {
                    control.GetType().GetMethod("OnParentBackColorChanged", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(control, new object[] { EventArgs.Empty });
                }
            }

            private Color skinTextColor = Color.Empty;
            private readonly Color defaultTextColor = SystemColors.ControlText;
            private Color textColor = Color.Empty;
            /// <summary>
            /// 文本颜色
            /// </summary>
            [Description("文本颜色")]
            [PropertyOrder(-193)]
            [SkinProperty(true, true)]
            public Color TextColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore() && this.skinTextColor != Color.Empty)
                    {
                        return this.skinTextColor;
                    }

                    if (this.textColor != Color.Empty)
                    {
                        return this.textColor;
                    }

                    if (((Control)this.owner).Parent != null)
                    {
                        return ((Control)this.owner).Parent.ForeColor;
                    }

                    return this.defaultTextColor;
                }
                set
                {
                    if (this.textColor == value)
                        return;

                    this.textColor = value;
                    ((Control)this.owner).Invalidate();

                    foreach (Control control in ((Control)this.owner).Controls)
                    {
                        control.GetType().GetMethod("OnParentForeColorChanged", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(control, new object[] { EventArgs.Empty });
                    }
                }

            }
            private bool ShouldSerializeTextColor()
            {
                return this.textColor != Color.Empty;
            }
            private void ResetTextColor()
            {
                this.textColor = Color.Empty;
                ((Control)this.owner).Invalidate();

                foreach (Control control in ((Control)this.owner).Controls)
                {
                    control.GetType().GetMethod("OnParentForeColorChanged", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(control, new object[] { EventArgs.Empty });
                }
            }

            #endregion

        }

        #endregion

    }

}
